/**
 * 
 */
package org.bookie.model;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.apache.commons.codec.digest.DigestUtils;
import org.hibernate.annotations.AccessType;
import org.hibernate.validator.NotNull;

/**
 * Class modelling a user. 
 * 
 * @author Igor Drobiazko
 */
@Entity
@AccessType("field")
@Table(name="Users")
public class User extends CommonEntity {

	private static final long serialVersionUID = 8111557981490419566L;
	
	/**Unique name of the user*/
	@Column(length = 25, nullable = false, unique = true, updatable=false)
	private String username;
	/**Password of the user*/
	@Column(name = "`PASSWORD`", length = 40, nullable = false)
	private String password;
	/**Email of the user*/
	@Basic @NotNull private String email;
	
	/** Date of the registration */
	@Column(nullable = false, updatable=false)
	private Date joined = new Date();
	
	@Embedded
	private Account account;
	
	@OneToMany(mappedBy="user",fetch=FetchType.LAZY)
	private List<BetSlip> betSlips = new ArrayList<BetSlip>();
	
	@Enumerated(EnumType.STRING) @NotNull 
	private Role role = Role.GUEST;
	
	/** Activation key */
	@Basic private String activationKey;
	
	/**List {@link Group}s this user is participating in*/
	@ManyToMany(targetEntity=Group.class)
	@JoinTable(
        name="UserGroups",
        joinColumns={@JoinColumn(name="USER_ID")},
        inverseJoinColumns={@JoinColumn(name="GROUP_ID")}
    )
	private List<Group> groups = new ArrayList<Group>();
	
	protected User(){super();}
	
	public User(String username, String password, String email){
		this.username = username;
		setPassword(password);
		setEmail(email);
		this.account = new Account(new Double(10));
		this.account.setOwner(this);
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}
	
	public void setPassword(String password) {
		this.password = encode(password);
	}
	
	public boolean hasPassword(String password){
		return this.password.equals(encode(password));
	}

	public Account getAccount() {
		return account;
	}

	public List<BetSlip> getBetSlips() {
		return betSlips;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public void setAccount(Account account) {
		this.account = account;
		account.setOwner(this);
	}

	public Role getRole() {
		return role;
	}

	public void setRole(Role role) {
		this.role = role;
	}
	/**
	 * Get the list {@link Group}s this user is member of
	 * @return List of Groups
	 */
	public List<Group> getGroups() {
		return groups;
	}
	
	/**
	 * Adds a {@link Group} to the list of user's groups
	 * @param group group to add
	 */
	public User addGroup(Group group){
		getGroups().add(group);
		group.getUsers().add(this);
		return this;
	}
	/**
	 * Get the list {@link Group}s this user is member of
	 * @param groups groups to set
	 */
	public void setGroups(List<Group> groups) {
		this.groups = groups;
	}
	/**
	 * Get the date of the registration
	 * @return instance of Date
	 */
	public Date getJoined() {
		return joined;
	}

	/**
	 * Method that calculates hashvalue that is used as a token for
	 * authentication of the user from public sources
	 * 
	 * @return
	 */
	public String calculateHash() {
		return encode(getEmail() + this.password);
	}
	
	/**
	 * Calculates the MD5 digest and returns the value as a 32 character
	 * @param value value to digest
	 * @return digest as a hex string
	 */
	private String encode(String value){
		return DigestUtils.md5Hex(value);
	}

	@Override
	public String toString() {
		return "User#" + getId() + "(" + getEmail() + ")";
	}
	
	/**
	 * Returns the activation key of the user.
	 */
	public String getActivationKey() {
		return activationKey;
	}
	
	/**Resets the activation key*/
	public String resetActivationKey(){
		activationKey = encode(getUsername()+System.currentTimeMillis());
		return getActivationKey();
	}
}
